﻿using System;
using System.Text;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.FxCop.Sdk;
using Community.StaticAnalysis.Rules.Tests.Dummies;
using Community.StaticAnalysis.Reliability.Rules;

namespace Community.StaticAnalysis.Rules.Tests.Reliability
{


    /// <summary>
    /// Test fixture contains test for the DiscoverDisposableObjectVisitor class
    /// 
    /// </summary>
    [TestClass]
    public class DiscoverDisposableObjectVisitorTestFixture
    {
        #region Test Methods

        [TestMethod]
        public void TestMethodContainsLocalThatIsNotDisposed()
        {
            const int EXPECTED_VARIABLE_COUNT = 1;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;


            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsLocalThatIsNotDisposed;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);
            visitor = CreateVisitor();

            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodCallsAMethodThatReturnsAObjectAndForgotToCallDispose()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 1;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameCallsAMethodThatReturnsAObjectAndForgotToCallDispose;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodCallConstructorWithoutStoringIt()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 1;
            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameCallConstructorWithoutStoringIt;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }


        [TestMethod]
        public void TestMethodContainsLocalThatIsDisposed()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsLocalThatIsDisposed;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);
            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodAssignToAField() 
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameAssignToAField;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodReturnsADisposableObject()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameReturnsADisposableObject;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();

            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodContainsDisposableObjectOutParam()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsDisposableObjectOutParam;
            Method method = CcUtil.GetFirstMethodMathingMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);
            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);

        }

        [TestMethod]
        public void TestMethodContainsDisposableObjectRefParam()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsDisposableObjectRefParam;
            Method method = CcUtil.GetFirstMethodMathingMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }


        [TestMethod]
        public void TestMethodReturnsObjectInsideTryBlock()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;
            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameReturnsObjectInsideTryBlock;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodCallsDisposeButNotInFinally()
        {
            const int EXPECTED_VARIABLE_COUNT = 1;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;
            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameCallsDisposeButNotInFinally;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }




        [TestMethod]
        public void TestMethodContainsForEachThatReturnsObject()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsForEachThatReturnsObject;

            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }


        [TestMethod]
        public void TestMethodContainsReturnsDisposableObjectWithIfElse()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsReturnsDisposableObjectWithIfElse;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);
            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodContainsReturnsDisposableObjectWithSwitch()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameContainsReturnsDisposableObjectWithSwitch;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodThatHasADisposableObjectAsParam()
        {
            const int EXPECTED_VARIABLE_COUNT = 0;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;

            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameThatHasADisposableObjectAsParam;
            Method method = CcUtil.GetFirstMethodMathingMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        [TestMethod]
        public void TestMethodThatHasAComplexFinally()
        {
            const int EXPECTED_VARIABLE_COUNT = 1;
            const int EXPECTED_METHOD_CALL_COUNT = 0;
            const int EXPECTED_CONSTRUCT_COUNT = 0;
            DiscoverDisposableObjectVisitor visitor;
            string methodName = ND2000SampleClass.MethodNameThatHasAComplexFinally;
            Method method = CcUtil.GetMethod(typeof(ND2000SampleClass), methodName);

            visitor = CreateVisitor();
            visitor.Visit(method);

            Verify(visitor, EXPECTED_VARIABLE_COUNT, EXPECTED_METHOD_CALL_COUNT, EXPECTED_CONSTRUCT_COUNT);
        }

        #endregion

        #region Utils

        private void Verify(DiscoverDisposableObjectVisitor visitor, int expectedVariableCount, int expectedMethodCallCount, int expectedConstructCallCount)
        {
            Assert.AreEqual(expectedVariableCount, visitor.VariableList.Count, "Invalid Variables count");
            Assert.AreEqual(expectedConstructCallCount, visitor.ConstructList.Count, "Invalid Construct count");
            Assert.AreEqual(expectedMethodCallCount, visitor.MethodCallList.Count, "Invalid MethodCall count");
        }

        private DiscoverDisposableObjectVisitor CreateVisitor()
        {
            DiscoverDisposableObjectVisitor visitor;

            visitor = new DiscoverDisposableObjectVisitor();

            return visitor;
        }

        #endregion
    }



}
